import json
import numpy as np
import datetime
import time
import os
from setting import Setting

def sample(preds, predictTotal=5):
  """
  从给定的preds中随机选择5个下标。
  当temperature固定时，preds中的值越大，选择其下标的概率就越大；
  当temperature不固定时，
      temperature越大，选择值小的下标的概率相对提高，
      temperature越小，选择值大的下标的概率相对提高。
  :param preds: 概率分布序列，其和为1.0
  :param temperature: 当temperature==1.0时，相当于直接对preds进行轮盘赌法
  :return:
  """
  preds = np.asarray(preds).astype(np.float64)
  exp_preds = np.exp(preds)
  preds2 = exp_preds / np.sum(exp_preds)
  responseTo = []
  while True:
    re = np.argmax(preds2)
    if re in responseTo:
      continue
    else:
      responseTo.append(re)
      preds2[re] = 0.0
    if len(responseTo) >= predictTotal:
      break
  return responseTo

def updateData(predicts_, predict_y):
  """ 统计所有结果里面，间隔多少个结果不对的情况
    :param predicts_: 测试的结果
    :param predict_y: 真实的结果
   """
  data = []
  correct = 0
  total =  len(predicts_)
  for i in range(total):
    balls= sample(predicts_[i])
    if predict_y[i] not in balls:
      correct = correct + 1
    else:
      data.append(correct)
      correct = 0
  print(data)
  return data

def updateMoney(data, moneyTpye=[1, 3, 7]):
  """ 统计在验证集中，模型的最终盈利情况 
    :param data: 统计所有结果里面，间隔多少个结果不对的情况。是updateData函数的返回值
    :param moneyTpye: 倍投类型
   """
  money = 0
  cur = 0
  min = 0
  max = 0
  for i in range(len(data)):
    if data[i] == 0:
      money = money +(moneyTpye[cur] * 4.8)
      cur = 0
    else:
      for j in range(data[i]):
        money = money - (moneyTpye[cur] * 5)
        cur = (cur + 1) % len(moneyTpye)
    if money > max:
      max = money
    if money < min:
      min = money
  print(money, min, max)

def curr_time():
  curr_time = datetime.datetime.now()
  curr_time = datetime.datetime.strftime(curr_time,'%Y-%m-%d %H:%M:%S')
  return curr_time

def Statistics(predicts_, predict_y, moneyTpye=[1], fileName=None, predictTotal=5):
  """ 根据预测值和真实值，统计模型的具体情况，判断模型是否可用。
    说明：这个是在10个号码中选5个下注，一注一元，所以一次就5元。每次只要预测正确，就赚4.8元
    :param predicts_: 测试的结果
    :param predict_y: 真实的结果
    :param moneyTpye: 倍投类型
   """
  money = 0
  cur = 0
  min = 0
  max = 0
  AccuracyNumber = 0 # 预测正确的个数
  AccuracyRate = 0. # 正确率
  total =  len(predicts_)
  for i in range(total):
    balls= sample(predicts_[i], predictTotal)
    if predict_y[i] in balls:
      money = money +(moneyTpye[cur] * 4.8)
      cur = 0
      AccuracyNumber = AccuracyNumber + 1
    else:
      money = money - (moneyTpye[cur] * 5)
      cur = (cur + 1) % len(moneyTpye)
    if money > max: max = money
    if money < min: min = money
  AccuracyRate = (AccuracyNumber / total) * 100
  currTime = curr_time()
  print("{}\t\t正确的个数为：{} / {}  -  {}%".format(fileName, AccuracyNumber, total, round(AccuracyNumber / total *100,2)))
  print("\t\t\t{} \t {} \t {}\n".format(round(money,2),round(min,2),round(max,2)))
  return {
    "total":total,
    "AccuracyNumber":AccuracyNumber,
    "AccuracyRate":round(AccuracyRate,2),
    "money":round(money,2),
    "min":round(min,2),
    "max":round(max,2),
    "moneyTpye":moneyTpye,
    "currTime":currTime,
    "fileName":fileName,
  }

def savaData(set,data={}):
  """ 将数据保存到本地文件。
    :param data: 要保存的数据。是一个对象。
   """
  path = os.path.split(os.path.realpath(__file__))[0]
  # 创建保存数据的文件
  try:
    f =open('{}/{}'.format(path,set.SavaDataFile),'r')
    f.close()
  except IOError:
    f = open('{}/{}'.format(path,set.SavaDataFile),'w')
  with open(path + "/" + set.SavaDataFile,'r') as load_f:
    try:
      load_dict = json.load(load_f)
    except Exception as e:
      load_dict = {} # 表示空白文件，则创建一个对象
  if len(load_dict) == 0: # 空文件，则直接存入
    load_dict[data["fileName"]] = [data]
  else:
    existence = False # 判断当前模型是否存在文件中.默认不在
    for key in load_dict:
      if key == data["fileName"]:
        existence = True
        load_dict[key].append(data)
    if not existence: # 表示该模型数据还没有存储过文件中
      load_dict[data["fileName"]] = [data]
  with open(path + "/" + set.SavaDataFile,"w") as f: # 将数据保存到文件中
    json.dump(load_dict,f,indent=2,ensure_ascii=True)
    print("加载入文件完成...")

class NpEncoder(json.JSONEncoder):
  def default(self, obj):
    if isinstance(obj, np.integer):
      return int(obj)
    elif isinstance(obj, np.floating):
      return float(obj)
    elif isinstance(obj, np.ndarray):
      return obj.tolist()
    elif isinstance(obj, datetime.datetime):
      return obj.strftime('%Y-%m-%dT%H:%M:%S')
    else:
      return super(NpEncoder, self).default(obj)

        
def savaAuthenticData(set,data={}):
  """ 将真实预测的数据保存到本地文件。真实预测未来数据
    :param data: 要保存的数据。是一个对象。
   """
  path = os.path.split(os.path.realpath(__file__))[0]
  # 创建保存数据的文件
  try:
    f =open('{}/{}'.format(path,set.SavaDataFile),'r')
    f.close()
  except IOError:
    f = open('{}/{}'.format(path,set.SavaDataFile),'w')
  with open(path + "/" + set.SavaDataFile,'r') as load_f:
    try:
      load_dict = json.load(load_f)
    except Exception as e:
      load_dict = {} # 表示空白文件，则创建一个对象
  if len(load_dict) == 0: # 空文件，则直接存入
    load_dict[data["fileName"]] = [data]
  else:
    existence = False # 判断当前模型是否存在文件中.默认不在
    for key in load_dict:
      if key == data["fileName"]:
        existence = True
        load_dict[key].append(data)
    if not existence: # 表示该模型数据还没有存储过文件中
      load_dict[data["fileName"]] = [data]
  with open(path + "/" + set.SavaDataFile,"w") as f: # 将数据保存到文件中
    json.dump(load_dict,f,indent=2,ensure_ascii=True,cls=NpEncoder)
    print("加载入文件完成...")

def sleeptime(hour, min=0, sec=0):
  # 返回休眠的秒数
  return hour * 3600 + min * 60 + sec

def whileFn(runFn, sleeptime, total=True):
  """ 循环执行指定的方法。默认为无限循环。
    :param runFn: 要执行的任务。是一个函数
    :param sleeptime: 间隔时长，是一个整数，表示多久执行一次runFn函数。单位是秒。
    :param total: 循环的次数。为True时无限循环；为False时直接退出；为整数时为循环多少次。
   """
  if isinstance(total, bool):
    while total:
      runFn()
      time.sleep(sleeptime)
  if isinstance(total, int):
    while total > 0:
      total = total-1
      runFn()
      time.sleep(sleeptime)

#判断变量类型的函数
def typeof(variate):
  type=None
  if isinstance(variate,int):
      type = "int"
  elif isinstance(variate,str):
      type = "str"
  elif isinstance(variate,float):
      type = "float"
  elif isinstance(variate,list):
      type = "list"
  elif isinstance(variate,tuple):
      type = "tuple"
  elif isinstance(variate,dict):
      type = "dict"
  elif isinstance(variate,set):
      type = "set" 
  arr = {"int":"整数","float":"浮点","str":"字符串","list":"列表","tuple":"元组","dict":"字典","set":"集合"}
  if not (type in arr):
      return "未知类型"
  return arr[type]